import {LocModel} from "../../../base/LocModel";
import {OrderId} from "../../../../../type/Type";
import {AttributeEnum, CastType1, HurtType} from "../../../../dataSource/DataModel";
import {IUnitAdapter} from "../../adapterInterface/model3/IUnitAdapter";
import {CodeUtil} from "../../../../codeAdapter/CodeUtil";
import {DataRouter} from "../../../../dataSource/DataRouter";
import {Logger} from "../../../config/Logger";


enum CustomData {
    dataA = 108,
    dataB = 109,
    dataC = 110,
    dataD = 111,
}

enum StateData {
    // 骰子数量
    dices = 0x10  ,
    // 骰子面数
    diceNum = 0x11,
    // 基础伤害
    baseHurt = 0x12,
    // 附加伤害
    addDamage = 0x13,
    // 攻击最小值
    mixAttack = 0x14,
    // 攻击最大值
    maxAttack = 0x15,
    // 攻击范围
    attackRange = 0x16,
    // 攻击间隔
    attackInterval = 0x25,
    // 攻击速度
    attackSpeed = 0x51,
    // 护甲
    defens = 0x20
}

interface AttributeToAbility {
    id: string,
    dateNum: number,
}

const attributeToAbilityMap: { [key: string]: AttributeToAbility } = {
    // 力量
    [AttributeEnum.strength]: {id: 'Aamk', dateNum: CustomData.dataC},
    // 敏捷
    [AttributeEnum.agile]: {id: 'Aamk', dateNum: CustomData.dataA},
    // 智力
    [AttributeEnum.intellect]: {id: 'Aamk', dateNum: CustomData.dataB},
    // 生命值
    [AttributeEnum.maxLife]: {id: 'AIl2', dateNum: CustomData.dataA},
    // 魔法值
    [AttributeEnum.maxMagic]: {id: 'AIbm', dateNum: CustomData.dataA},
    // // 攻击力
    // [AttributeEnum.attack]: { id: 'AItg', dateNum: CustomData.dataA },
    // 护甲
    [AttributeEnum.defense]: {id: 'AId1', dateNum: CustomData.dataA},
    // ----------------------------------------------------------------------------------------------------------------------

    // 技能效果加成
    // 生命回复速度
    [AttributeEnum.lifeRecovery]: {id: 'Arel', dateNum: CustomData.dataA},
    // 移动速度
    [AttributeEnum.speed]: {id: 'AIms', dateNum: CustomData.dataA},
    // 攻击速度
    [AttributeEnum.attackSpeed]: {id: 'AIsx', dateNum: CustomData.dataA},
    // 魔法恢复速度
    [AttributeEnum.magicRecovery]: {id: 'AIrm', dateNum: CustomData.dataA},
}

export class UnitAdapter implements  IUnitAdapter {
    addAbility(handle: any, abilityId: number | string): boolean {
        if (this.isValid(handle)) {
            return UnitAddAbility(handle, abilityId);
        }
        return false;
    }
    addSleepPerm(handle: any, add: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitAddSleepPerm(handle, add);
    }
    applyTimedLife(handle: any, buffId: number | string, duration: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitApplyTimedLife(handle, buffId, duration);
    }
    bindHandle(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        handle_ref(handle)
    }

    canSleepPerm(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitCanSleepPerm(handle);
    }

    createHandle(owner: number, id: string, loc: LocModel, face: number): any {
        const p = Player(owner);
        if (face) {
        } else {
            face = 0;
        }
        const unit = CreateUnit(p, id, loc.x, loc.y, face);
        return unit;
    }

    decAbilityLevel(handle: any, abilCode: number): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return DecUnitAbilityLevel(handle, abilCode);
    }

    destroy(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        RemoveUnit(handle);
        handle_unref(handle);
    }

    equal(handle1: any, handle2: any): boolean {
        if (this.isValid(handle1) && this.isValid(handle2)) {
        } else {
            return false;
        }
        return GetHandleId(handle1) === GetHandleId(handle2);
    }

    getAbilityLevel(handle: any, abilCode: string): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitAbilityLevel(handle, abilCode);
    }

    getAcquireRange(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitAcquireRange(handle);
    }

    getAgility(handle: any, includeBonuses: boolean): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetHeroAgi(handle, includeBonuses);
    }

    getAttackDistance(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, ConvertUnitState(0x16));
    }

    getAttackSpeed(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, ConvertUnitState(0x51));
    }

    getAttackSpeedInterval(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, ConvertUnitState(0x25));
    }

    getCanSleep(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitCanSleep(handle);
    }

    getCurrentOrder(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitCurrentOrder(handle);
    }

    getDefaultAcquireRange(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitDefaultAcquireRange(handle);
    }

    getDefaultFlyHeight(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitDefaultFlyHeight(handle);
    }

    getDefaultMoveSpeed(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitDefaultMoveSpeed(handle);
    }

    getDefaultPropWindow(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitDefaultPropWindow(handle);
    }

    getDefaultTurnSpeed(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitDefaultTurnSpeed(handle);
    }

    getExperience(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetHeroXP(handle);
    }

    getFacing(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitFacing(handle);
    }

    getIgnoreAlarm(handle: any, flag: boolean): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitIgnoreAlarm(handle, flag);
    }

    getIgnoreAlarmToggled(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitIgnoreAlarmToggled(handle);
    }

    getIntelligence(handle: any, includeBonuses: boolean): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetHeroInt(handle, includeBonuses);
    }

    getInventorySize(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return UnitInventorySize(handle);
    }

    getLevel(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitLevel(handle);
    }

    getLife(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, UNIT_STATE_LIFE);
    }

    getLifePercent(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitLifePercent(handle) / 100;
    }

    getLoc(handle: any): LocModel {
        const x = GetUnitX(handle);
        const y = GetUnitY(handle);
        const height = this.getflyHeight(handle);
        const locModel: LocModel = new LocModel(x, y, height);
        return locModel;
    }

    getMana(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, UNIT_STATE_MANA);
    }

    getManaPercent(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitManaPercent(handle) / 100;
    }

    getMaxLife(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, UNIT_STATE_MAX_LIFE);
    }

    getMaxMana(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitState(handle, UNIT_STATE_MAX_MANA);
    }

    getMoveSpeed(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitMoveSpeed(handle);
    }

    getName(handle: any): string {
        if (this.isValid(handle)) {
        } else {
            return '';
        }
        return GetUnitName(handle);
    }

    getPaused(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return IsUnitPaused(handle);
    }

    getPropWindow(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitPropWindow(handle);
    }

    getShow(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return !IsUnitHidden(handle);
    }

    getSleeping(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitIsSleeping(handle);
    }

    getStrId(handle: any): string {
        if (this.isValid(handle)) {
        } else {
            return '';
        }
        return id2string(GetUnitTypeId(handle));
    }

    getStrength(handle: any, includeBonuses: boolean): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetHeroStr(handle, includeBonuses);
    }

    getTurnSpeed(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitTurnSpeed(handle);
    }

    getflyHeight(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return 0;
        }
        return GetUnitFlyHeight(handle);
    }

    hasAbility(handle: any, abilId: string): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return GetUnitAbilityLevel(handle, FourCC(abilId)) > 0;
    }

    isHero(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        const typeId = GetUnitTypeId(handle);
        return IsHeroUnitId(typeId);
    }

    isValid(handle: any): boolean {
        const typeId = GetUnitTypeId(handle);
        if (handle && IsHandle(handle) && typeId && typeId > 0) {
            return true;
        }
        return false;
    }

    issueBuildOrder(handle: any, unit: string | number, loc: LocModel): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        let ret;
        if (typeof unit === "string") {
            ret = IssueBuildOrder(handle, unit, loc.x, loc.y)
        } else{
            ret = IssueBuildOrderById(handle, unit, loc.x, loc.y);
        }
        return ret;
    }

    issueImmediateOrder(handle: any, order: string | OrderId): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        let ret;
        if (typeof order === "string") {
            ret = IssueImmediateOrder(handle, order)
        } else{
            ret = IssueImmediateOrderById(handle, order)
        }
        return ret;
    }

    issueOrderAt(handle: any, order: string | OrderId, loc: LocModel): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        let ret;
        if (typeof order === "string") {
            ret = IssuePointOrder(handle, order, loc.x, loc.y)
        } else{
            ret = IssuePointOrderById(handle, order, loc.x, loc.y)
        }
        return ret;
    }

    issueTargetOrder(handle: any, order: string | OrderId, targetWidget: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        let ret;
        if (typeof order === "string") {
            ret = IssueTargetOrder(handle, order, targetWidget)
        } else{
            ret = IssueTargetOrderById(handle, order, targetWidget);
        }
        return ret;
    }

    kill(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        KillUnit(handle);
    }

    pauseTimedLife(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitPauseTimedLife(handle, flag);
    }

    recycleGuardPosition(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        RecycleGuardPosition(handle);
    }

    removeAbility(handle: any, abilityId: number | string): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitRemoveAbility(handle, abilityId);
    }

    removeGuardPosition(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        RemoveGuardPosition(handle);
    }

    resetCooldown(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitResetCooldown(handle);
    }

    revive(handle: any, loc: LocModel, doEyecandy: boolean): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        const ret = ReviveHero(handle, loc.x, loc.y, doEyecandy);
        return ret;
    }

    select(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        ClearSelection();
        SelectUnit(handle, flag);
    }

    setAbilityLevel(handle: any, abilCode: number | string, level: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitAbilityLevel(handle, abilCode, level);
    }

    setAcquireRange(handle: any, value: number): any {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        SetUnitAcquireRange(handle, value);
    }

    setAgility(handle: any, value: number, permanent: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetHeroAgi(handle, value, permanent);
    }

    setAnimation(handle: any, whichAnimation: string): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        if (typeof whichAnimation === "string") {
            SetUnitAnimation(handle, whichAnimation);
        }
    }

    setAttackDistance(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle, ConvertUnitState(0x16), value);
    }

    setAttackSpeed(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle, ConvertUnitState(0x51), value);
    }

    setAttackSpeedInterval(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle, ConvertUnitState(0x25), value);
    }

    setBlendTime(handle: any, timeScale: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitBlendTime(handle, timeScale);
    }

    setCanSleep(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitAddSleep(handle, flag);
    }

    setCreepGuard(handle: any, creepGuard: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitCreepGuard(handle, creepGuard);
    }

    setExperience(handle: any, newXpVal: number, showEyeCandy: boolean = true): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetHeroXP(handle, newXpVal, showEyeCandy);
    }

    public refreshUnitAbilityData(handle: any, abilityId: string, data_type: CustomData, value: number) {
        if (this.isValid(handle)) {
        } else {
            return false;
        }

        if (GetUnitAbilityLevel(handle, abilityId) <= 0) {
            UnitAddAbility(handle, abilityId)
            let ability = EXGetUnitAbility(handle, abilityId)
            EXSetAbilityDataReal(ability, 1, CustomData.dataD, 1)//dataD 隐藏图标
            EXSetAbilityDataReal(ability, 1, CustomData.dataA, 0)
            EXSetAbilityDataReal(ability, 1, CustomData.dataB, 0)
            EXSetAbilityDataReal(ability, 1, CustomData.dataC, 0)
        }
        if (GetUnitAbilityLevel(handle, abilityId) > 0) {
            let ability = EXGetUnitAbility(handle, abilityId)
            if (IsHandle(ability)) {
                IncUnitAbilityLevel(handle, abilityId)
                EXSetAbilityDataReal(ability, 1, data_type, value)
                DecUnitAbilityLevel(handle, abilityId)
            }
            // else {
            //     SysToastUtil.toastError('请配置映射对应技能');
            // }
        }
        // else {
        //     SysToastUtil.toastError('技能添加失败！');
        // }
    }


    setExtraAttr(handle: any, val: number, targetAttr: AttributeEnum): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        const attributeToAbility:AttributeToAbility = attributeToAbilityMap[targetAttr];
        if (attributeToAbility) {
            const abilityId = attributeToAbility.id;
            const dataType = attributeToAbility.dateNum;
            this.refreshUnitAbilityData(handle, abilityId, dataType, val);
        }
    }

    setFacing(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitFacing(handle, value);
    }

    setIntelligence(handle: any, value: number, permanent: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetHeroInt(handle, value, permanent);
    }

    setLevel(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetHeroLevel(handle, value, true);
    }

    setLife(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle,UNIT_STATE_LIFE, value);
    }

    setLifePercent(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitLifePercentBJ(handle, value * 100);
    }

    setLoc(handle: any, locModel: LocModel): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitPosition(handle, locModel.x, locModel.y);
        const z = locModel.z;
        // const height = this.getflyHeight();
        if (!CodeUtil.isNull(z)) {
            this.setflyHeight(handle, z, 0);
        }
    }

    setMana(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle, UNIT_STATE_MANA, value);
    }

    setManaPercent(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitManaPercentBJ(handle, value * 100);
    }

    setMaxLife(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle, UNIT_STATE_MAX_LIFE, value);
    }

    setMaxMana(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitState(handle, UNIT_STATE_MAX_MANA, value);
    }

    setModelPath(handle: any, path: string): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        DzSetUnitModel(handle, path);
    }

    setMoveSpeed(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitMoveSpeed(handle, value);
    }

    setPathing(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitPathing(handle, flag);
    }

    setPaused(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        PauseUnit(handle, flag);
    }

    setPropWindow(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitPropWindow(handle, value);
    }

    setScale(handle: any, scaleX: number, scaleY: number, scaleZ: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitScale(handle, scaleX, scaleY, scaleZ);
    }

    setShow(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        ShowUnit(handle, flag);
    }

    setStrength(handle: any, value: number, permanent: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetHeroStr(handle, value, permanent);
    }

    setTimeScale(handle: any, timeScale: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitTimeScale(handle, timeScale);
    }

    setTurnSpeed(handle: any, value: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitTurnSpeed(handle, value);
    }

    setUnitIcon(handle: any, path: string): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        // SetUnitPortrait(handle, path);
    }

    setUseAltIcon(handle: any, flag: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitSetUsesAltIcon(handle, flag);
    }

    setUseFood(handle: any, useFood: boolean): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitUseFood(handle, useFood);
    }

    setVertexColor(handle: any, red: number, green: number, blue: number, alpha: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitVertexColor(handle, red, green, blue, alpha);
    }

    setflyHeight(handle: any, value: number, rate: number): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        SetUnitFlyHeight(handle, value, rate);
    }

    wakeUp(handle: any): void {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        UnitWakeUp(handle);
    }

    damage(handle1: any, handle2: any, hurtValue: number, hurtType: HurtType): void {
        if (this.isValid(handle1) && this.isValid(handle2)) {
        } else {
            return;
        }
        let damageType;
        if (hurtType === HurtType.physics || hurtType === HurtType.hero) {
            damageType = DAMAGE_TYPE_NORMAL;
        } else {
            damageType = DAMAGE_TYPE_MAGIC;
        }
        UnitDamageTargetBJ(handle1, handle2, hurtValue, ATTACK_TYPE_MAGIC, damageType);
    }

    getOwnerId(handle: any): number {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        return GetPlayerId(GetOwningPlayer(handle));
    }

    useAbility(handle: any, abilityId: string, targetLoc: LocModel, target: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return;
        }
        const abilityData = DataRouter.getAbilityDataById(abilityId);
        let ret = false;
        const cast_type1 = abilityData.cast_type1;
        const strOrder = abilityData.Order;
        switch (cast_type1) {
            case CastType1.unit:{
                ret = this.issueTargetOrder(handle, strOrder, target);
                break;
            }
            case CastType1.point:{
                ret = this.issueOrderAt(handle, strOrder, targetLoc);
                break;
            }
            case CastType1.null:{
                ret = this.issueImmediateOrder(handle, strOrder);
                break;
            }
        }
        return ret;
    }

    isVertigo(handle: any): boolean {
        if (this.isValid(handle)) {
        } else {
            return false;
        }
        return UnitHasBuffBJ(handle, FourCC('BPSE'))
    }
    // todo 【需要被回退】
    giveItem(handle1: any, handle2: any, index: number): boolean {
        if (this.isValid(handle1)) {
        } else {
            return false;
        }
        return UnitAddItem(handle1, handle2);
    }
}
